using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;

public class ObjectFactoryDict : IDictionary<FactoryType, ObjectFactory>
{
	// Internal (wrapped) dictionary
	private Dictionary<FactoryType, ObjectFactory> _factories = new Dictionary<FactoryType, ObjectFactory>();
	
	public ObjectFactory Create(FactoryType type)
	{
		ObjectFactory factory = new ObjectFactory(type);
		if(_factories.ContainsKey(type))
		{
			Debug.LogError("already contain this kind of factory!");
			return null;
		}
		_factories[type] = factory;
		return factory;
	}
	
	public override string ToString()
	{
		var typesArray = new FactoryType[this._factories.Count];
		this._factories.Keys.CopyTo(typesArray, 0);
		var keysArray = new string[this._factories.Count];
		for(int i=0;i<keysArray.Length;i++)
		{
			keysArray[i] = typesArray[i].ToString();
		}
		return string.Format("[{0}]", System.String.Join(", ", keysArray));
	}
	
	public bool Destroy(FactoryType type)
	{
		// Use TryGetValue to avoid KeyNotFoundException.
		//   This is faster than Contains() and then accessing the dictionary
		ObjectFactory factory;
		if (!this._factories.TryGetValue(type, out factory))
		{
			Debug.LogError(string.Format("ObjectFactoryManager: Unable to destroy '{0}'. Not in ObjectFactoryManager",type));
			return false;
		}
		
		_factories.Remove(type);
		
		return true;
	}

	public void DestroyAll()
	{
		foreach (KeyValuePair<FactoryType, ObjectFactory> pair in _factories)
			pair.Value.Clear();
		this._factories.Clear();
	}

	
	public void Add(FactoryType type, ObjectFactory factory)
	{
		string msg = "using Create interface instead";
		Debug.LogError(msg);
		throw new System.NotImplementedException(msg);
	}

	public bool Remove(FactoryType type)
	{
		string msg = "using DestoryAll interface instead";
		Debug.LogError(msg);
		throw new System.NotImplementedException(msg);
		return false;
	}
	
	public int Count { get { return this._factories.Count; } }
	
	public bool ContainsKey(FactoryType type)
	{
		return this._factories.ContainsKey(type);
	}

	public bool Contains(KeyValuePair<FactoryType,ObjectFactory> item)
	{
		return this._factories.ContainsKey(item.Key);
	}
	
	public bool TryGetValue(FactoryType type, out ObjectFactory factory)
	{
		return this._factories.TryGetValue(type, out factory);
	}
	
	public ObjectFactory this[FactoryType key]
	{
		get
		{
			ObjectFactory factory;
			try
			{
				factory = this._factories[key];
			}
			catch (KeyNotFoundException)
			{
				string msg = string.Format("A Factory with the name '{0}' not found. " +
				                           "\nPools={1}",
				                           key, this.ToString());
				throw new KeyNotFoundException(msg);
			}
			
			return factory;
		}
		set
		{
			string msg = "Cannot set ObjectFactoryManager[key] directly. Use Create instead";
			throw new System.NotImplementedException(msg);
		}
	}
	
	public ICollection<FactoryType> Keys
	{
		get
		{
			return this._factories.Keys;
		}
	}
	
	
	public ICollection<ObjectFactory> Values
	{
		get
		{
			return this._factories.Values;
		}
	}

	
	public void Add(KeyValuePair<FactoryType, ObjectFactory> item)
	{
		string msg = "use Create instead";
		throw new System.NotImplementedException(msg);
	}
	
	public void Clear()
	{
		string msg = "Use DestroyAll() instead.";
		throw new System.NotImplementedException(msg);
		
	}
	
	private void CopyTo(KeyValuePair<FactoryType, ObjectFactory>[] array, int arrayIndex)
	{
		string msg = "cannot be copied";
		throw new System.NotImplementedException(msg);
	}

	void ICollection<KeyValuePair<FactoryType, ObjectFactory>>.CopyTo(KeyValuePair<FactoryType, ObjectFactory>[] array, int arrayIndex)
	{
		string msg = "cannot be copied";
		throw new System.NotImplementedException(msg);
	}
	
	public bool Remove(KeyValuePair<FactoryType, ObjectFactory> item)
	{
		string msg = "can only be destroyed, not removed and kept alive use DestroyAll";
		throw new System.NotImplementedException(msg);
	}

	public IEnumerator<KeyValuePair<FactoryType, ObjectFactory>> GetEnumerator()
	{
		return this._factories.GetEnumerator();
	}

	System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
	{
		return this._factories.GetEnumerator();
	}

	private bool IsReadOnly { get { return true; } }
	bool ICollection<KeyValuePair<FactoryType, ObjectFactory>>.IsReadOnly { get { return true; } }
}
